#include "stdafx.h"
#include "main_generator.h"


char next(char **pre_processed_source) {
	char c = **pre_processed_source;
	(*pre_processed_source)++;

	return c;
}

void unnext(char **pre_processed_source, int offset) {
	(*pre_processed_source) -= offset;
}

int valid(char *source) {
	int stack_count = 0;
	while(*source != 0) {
		if(*source == '[' || *source == '{' || *source == '(') {
			stack_count++;
		} else if(*source == ']' || *source == '}' || *source == ')') {
			stack_count--;
		}
		source++;
	}

	return stack_count == -1;
}

result_state ready(char *pre_processed_source) {
	if(!pre_processed_source)
		return not_existed_source;
	else if(!valid(pre_processed_source))
		return not_parsing;

	return none;
}

bool call_detected(detected_callback detected_function, char **pre_processed_source, CFG *cfg, List *last_block_list, char *str, int *str_index) {
	result res;
	unnext(pre_processed_source, strlen("for"));
	if(detected_function(cfg,  &res, pre_processed_source) == false) {
		return false;
	}

	attach_basic_block_multi_parent(cfg, last_block_list, res.start);
	reset_list(last_block_list);
	merge_list(last_block_list, res.ends);
	destroy_list(res.ends);

	memset(str, 0, 1024);
	*str_index = 0;

	return true;
}

result_state parsing(CFG *cfg, char **pre_processed_source) {
	char c, str[1024];
	int strIndex = 0;
	List *last_block_list = create_list();
	result res = { 0, 0 };

	memset(str, 0, 1024);
	while((c = next(pre_processed_source)) != 0) {
		if(!(strIndex == 0 && is_whitespace(c))) {
			str[strIndex++] = c;
			if(c == '}') {
				make_end(last_block_list, cfg);
				destroy_list(last_block_list);
				last_block_list = 0;
				break;
			} else if(c == ';') { // statement

				BasicBlock *bb = make_basic_block(ct_statement, str);
				attach_basic_block_multi_parent(cfg, last_block_list, bb);
				last_block_list = reset_list(last_block_list);
				add_list(last_block_list, bb);

				memset(str, 0, 1024);
				strIndex = 0;
			} else if(!strncmp(str, "if", strlen("if"))) { // detected_if
				result res;
				unnext(pre_processed_source, strlen("if"));
				if(detected_if(cfg, &res, pre_processed_source) == false) {
					destroy_list(res.ends);
					return not_parsing;
				}

				attach_basic_block_multi_parent(cfg, last_block_list, res.start);
				destroy_list(last_block_list);
				last_block_list = res.ends;
				

				memset(str, 0, 1024);
				strIndex = 0;

				// printf("detected_if\n");
			} else if(!strncmp(str, "for", strlen("for"))) {
				result res;
				unnext(pre_processed_source, strlen("for"));
				if(detected_for(cfg,  &res, pre_processed_source) == false) {
					return not_parsing;
				}

				attach_basic_block_multi_parent(cfg, last_block_list, res.start);
				destroy_list(last_block_list);
				last_block_list = res.ends;

				memset(str, 0, 1024);
				strIndex = 0;

				// detected_for
			} else if(!strncmp(str, "while", strlen("while"))) {
				if(call_detected(detected_while, pre_processed_source, cfg, last_block_list, str, &strIndex) == false) {
					return not_parsing;
				}

				//result res;
				//unnext(pre_processed_source, strlen("for"));
				//if(detected_while(cfg,  &res, pre_processed_source) == false) {
				//	return false;
				//}

				//attach_basic_block_multi_parent(cfg, last_block_list, res.start);
				//destroy_list(last_block_list);
				//last_block_list = res.ends;

				//memset(str, 0, 1024);
				//strIndex = 0;

				// detected_while
			} else if(!strncmp(str, "switch", strlen("switch"))) { // detected_switch
				result res;
				unnext(pre_processed_source, strlen("switch"));
				if(detected_switch(cfg, &res, pre_processed_source) == false) {
					return not_parsing;
				}
				
				attach_basic_block_multi_parent(cfg, last_block_list, res.start);
				destroy_list(last_block_list);
				last_block_list = res.ends;

				memset(str, 0, 1024);
				strIndex = 0;
			}
		}
	}

	if(last_block_list) destroy_list(last_block_list);

	return none;
}

bool parse(CFG *cfg, char *pre_processed_source) {
	
	result_state rs = none;

	rs = ready(pre_processed_source);

	if(rs == none) 
		rs = parsing(cfg, &pre_processed_source);

	return print(rs);
}

bool print(result_state rs) {
	switch(rs) {
	case none:
		printf("Success!!\n");
		break;
	case not_parsing:
		printf("Error!!\n");
		break;
	case not_existed_source:
		printf("./CG <source file(*.c)> <report file> \n");
		break;
	}

	return rs == none;
}